package edu.stanford.prpl.app.prpltalk;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URISyntaxException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import edu.stanford.prpl.api.BlobResource;
import edu.stanford.prpl.api.Identity;
import edu.stanford.prpl.api.PRPLAppClient;
import edu.stanford.prpl.api.QueryResultIterator;
import edu.stanford.prpl.api.PRPLObjectManager.BlobManager;
import edu.stanford.prpl.common.PRPLProperties;
import edu.stanford.prpl.common.util.URIUtils;
import edu.stanford.prpl.impl.DeviceImpl;
import edu.stanford.prpl.impl.app.PRPLAppClientImpl;
import edu.stanford.prpl.impl.app.PRPLAppClientImpl.PRPLBlobServerAppClient;

/**
 * PrPlTalk client and text-based sample chat
 * 
 * @author sseong
 * 
 */

public class PRPLTalk {

	private static Log log = LogFactory.getLog(PRPLTalk.class);

	public static String RESOURCE_COMMUNICATION_TYPE_URI = "http://prpl.stanford.edu/#Communication";
	public static String PROPERTY_RECIPIENT_URI = "http://prpl.stanford.edu/#recipient";

	public static String PROPERTY_SENDER_URI = "http://prpl.stanford.edu/#sender";
	public static String PROPERTY_MESSAGE_COUNT_URI = "http://prpl.stanford.edu/#msgCount";
	public static String PROPERTY_SESSION_ID_URI = "http://prpl.stanford.edu/#sessionId";

	PRPLAppClient prplAppClient;
	Map<String, Message[]> sessionId2Messages;

	URL callbackURL;
	Thread watcherWorker;
	Notification notification;
	Map<String, Set<AsynchCallback>> callbackMap;

	public PRPLTalk() {
		this.prplAppClient = PRPLAppClientImpl.newInstance();
		this.sessionId2Messages = new HashMap<String, Message[]>();
		this.notification = new Notification();
		this.callbackURL = DeviceImpl.getCurrentDevice().getServerURL();
		this.callbackMap = new HashMap<String, Set<AsynchCallback>>();
		this.startWebServer();
	}

	public String sessionId2ResourceURI(String sessionId) {
		return sessionId;
	}

	public String resourceURI2sessionId(String resourceURI) {
		return resourceURI;
	}

	public PRPLAppClient getPRPLAppClient() {
		return this.prplAppClient;
	}

	/**
	 * Start a new session
	 * 
	 * @return sessionId
	 */
	public String startSession(String... prplURIs) {
		BlobResource blobResource = this.createCommunicationResource(prplURIs);
		log.debug("Starting Session Id: " + blobResource.getURI());
		return blobResource.getURI();
	}

	/**
	 * Close this session
	 * 
	 * @param sessionId
	 */
	public void endSession(String sessionId) {
		log.debug("Ending Session Id: " + sessionId);
	}

	/**
	 * Join previously created session
	 * 
	 * @param sessionId
	 * @return
	 */
	public boolean joinSession(String sessionId) {

		String query = "SELECT DISTINCT ?resource WHERE { ?resource rdf:type <" + RESOURCE_COMMUNICATION_TYPE_URI
				+ ">. " + " ?resource <" + PROPERTY_SESSION_ID_URI + "> \"" + sessionId + "\"^^xsd:string . "
				+ "} ";

		log.debug(query);

		QueryResultIterator queryResult = this.prplAppClient.getResourceManager().runQuery(query);

		if (queryResult.hasNext()) {
			BlobResource blobResource = queryResult.next().getBlobResource("resource");
			log
					.debug("Found a resource with Session Id: " + sessionId + "\tResource Id: "
							+ blobResource.getURI());
			return true;
		}

		log.debug("Failed to find a resource with Session Id: " + sessionId);
		return false;
	}

	/**
	 * Invite other users to this session
	 * 
	 * @param sessionId
	 * @param prplURIs
	 */
	public void invite(String sessionId, String... prplURIs) {
		String resourceURI = this.sessionId2ResourceURI(sessionId);
		BlobResource blobResource = prplAppClient.getResourceManager().getBlobResource(resourceURI);

		for (String prplURI : prplURIs) {

			log.debug("Inviting(sharing with) " + prplURI);

			if (URIUtils.isIdentityURI(prplURI)) {
				// Create if not exists
				prplAppClient.getIdentityManager().getIdentityByURI(prplURI, true);
				// Share with this identity
				prplAppClient.getResourceManager().shareResourceWithIdentities(blobResource.getURI(), prplURI);

				// Sync
				this.synchWith(prplURI);

			} else if (URIUtils.isGroupURI(prplURI)) {
				// Share with this group
				prplAppClient.getResourceManager().shareResourceWithGroups(blobResource.getURI(), prplURI);
			}

			prplAppClient.getResourceManager().addResourceMetaData(blobResource.getURI(), PROPERTY_RECIPIENT_URI,
					prplURI);
		}
	}

	/**
	 * Create a new blob resource of type Communication
	 * 
	 * @param identityURI
	 * @return
	 */
	private BlobResource createCommunicationResource(String... prplURIs) {

		// Create a new blob communication resource
		BlobResource blobResource = prplAppClient.getResourceManager().createBlobResource();
		blobResource.addType("http://prpl.stanford.edu/#Communication");
		blobResource.setName("Communication");

		// Set default blob path
		prplAppClient.getBlobManager().setResourceBlobSourceURI(blobResource.getURI(), null);

		for (String prplURI : prplURIs) {

			if (URIUtils.isIdentityURI(prplURI)) {
				// Create if not exists
				prplAppClient.getIdentityManager().getIdentityByURI(prplURI, true);
				// Share with this identity
				prplAppClient.getResourceManager().shareResourceWithIdentities(blobResource.getURI(), prplURI);

				// Sync
				this.synchWith(prplURI);

			} else if (URIUtils.isGroupURI(prplURI)) {
				// Share with this group
				prplAppClient.getResourceManager().shareResourceWithGroups(blobResource.getURI(), prplURI);

			}

			prplAppClient.getResourceManager().addResourceMetaData(blobResource.getURI(), PROPERTY_RECIPIENT_URI,
					prplURI);
		}

		// Get session Id
		String sessionId = this.resourceURI2sessionId(blobResource.getURI());

		prplAppClient.getResourceManager().setResourceMetaData(blobResource.getURI(), PROPERTY_SESSION_ID_URI,
				sessionId);

		// Set msgCount to 0
		// prplAppClient.getResourceManager().setResourceMetaData(blobResource.getURI(),
		// PROPERTY_MESSAGE_COUNT_URI,
		// "0");

		log.debug("Created a resource with " + Arrays.toString(prplURIs));

		return blobResource;
	}

	/**
	 * Get an array of all communication blob resources
	 * 
	 * @return
	 */
	public BlobResource[] getAllCommunicationResources() {

		List<BlobResource> resources = new ArrayList<BlobResource>();

		String query = "SELECT DISTINCT ?resource WHERE { ?resource rdf:type <" + RESOURCE_COMMUNICATION_TYPE_URI
				+ ">. " + " ?resource prpl:modifiedDate ?modifiedDate . " + "} ORDER BY DESC(?modifiedDate)";

		log.debug(query);

		QueryResultIterator queryResult = this.prplAppClient.getResourceManager().runQuery(query);
		while (queryResult.hasNext()) {
			QueryResultIterator.Solution solution = queryResult.next();
			BlobResource r = solution.getBlobResource("resource");
			if (r != null)
				resources.add(r);
		}

		log.debug("# of all communication resources found: " + resources.size());
		return resources.toArray(new BlobResource[] {});
	}

	/**
	 * Get all communication blob resources with this URI
	 * 
	 * @param prplURI
	 * @return
	 */
	public BlobResource[] getAllCommunicationResourcesWith(String prplURI) {

		List<BlobResource> resources = new ArrayList<BlobResource>();

		String query = "SELECT DISTINCT ?resource WHERE { ?resource rdf:type <" + RESOURCE_COMMUNICATION_TYPE_URI
				+ ">. " + " ?resource ?p ?o FILTER ( "
				+ " (?p = <http://prpl.stanford.edu/#recipient> && (?o = \"" + prplURI
				+ "\"^^xsd:string || ?o =  \"" + prplURI + "\")) "
				+ " || (?p = <http://prpl.stanford.edu/#owner> && (?o = \"" + prplURI + "\"^^xsd:string ||?o = \""
				+ prplURI + "\")) ). " + " ?resource prpl:modifiedDate ?modifiedDate . "
				+ "} ORDER BY DESC(?modifiedDate)";
		log.debug(query);

		QueryResultIterator queryResult = this.prplAppClient.getResourceManager().runQuery(query);
		while (queryResult.hasNext()) {
			QueryResultIterator.Solution solution = queryResult.next();
			BlobResource r = solution.getBlobResource("resource");
			if (r != null)
				resources.add(r);
		}
		log.debug("# of communication resources found: " + resources.size());
		return resources.toArray(new BlobResource[] {});
	}

	/**
	 * Get a message in this session with offset msgId
	 * 
	 * @param sessionId
	 * @param msgId
	 * @return
	 */
	public Message getMessage(String sessionId, int msgId) {
		Message[] messages = this.sessionId2Messages.get(sessionId);
		if (messages.length > msgId)
			return messages[msgId];
		else {
			messages = this.getMessages(sessionId, true);
			if (messages.length > msgId)
				return messages[msgId];
		}
		return null;
	}

	/**
	 * Get all messages in this session
	 * 
	 * @param sessionId
	 * @param refresh
	 * @return
	 */
	public Message[] getMessages(String sessionId, boolean refresh) {

		if (!refresh) {
			return this.sessionId2Messages.get(sessionId);
		}

		String resourceURI = this.sessionId2ResourceURI(sessionId);

		List<Message> messages = new ArrayList<Message>();
		InputStream in = prplAppClient.getBlobManager().getResourceBlob(resourceURI);
		if (in != null) {

			String readLine = null;
			BufferedReader br = new BufferedReader(new InputStreamReader(in));

			try {

				ByteArrayOutputStream bout = new ByteArrayOutputStream();
				// boolean isEndOfMessage = false;
				boolean isStartOfNewMessage = false;

				while (true) {

					readLine = br.readLine();
					isStartOfNewMessage = (readLine == null) ? true : readLine.matches("From .*");

					if (isStartOfNewMessage && bout.size() > 0) {
						// Write out previous msg
						Message message = new Message(new ByteArrayInputStream(bout.toByteArray()));
						messages.add(message);
						// try {
						// Session session = Session.getDefaultInstance(System.getProperties());
						// Message message = new MimeMessage(session,
						// new ByteArrayInputStream(bout.toByteArray()));
						//
						// // TODO: Revisite this
						// message.setText(message.getContent().toString().trim());
						// messages.add(message);
						// } catch (MessagingException e) {
						// // TODO Auto-generated catch block
						// e.printStackTrace();
						// }
						// Clean buffer for a new msg
						bout = new ByteArrayOutputStream();

					}

					if (readLine == null)
						// End of file
						break;
					else {
						readLine += "\n";
						bout.write(readLine.getBytes());
					}

				}

			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}
		this.sessionId2Messages.put(sessionId, messages.toArray(new Message[] {}));
		return this.sessionId2Messages.get(sessionId);
	}

	/**
	 * Print messages in this session to STOUT
	 * 
	 * @param sessionId
	 */
	public void printMessages(String sessionId) {
		System.out.println("------------------------------------------");
		Message[] messages = this.getMessages(sessionId, false);
		if (messages == null)
			messages = this.getMessages(sessionId, true);
		if (messages != null) {
			for (int i = 0; i < messages.length; i++) {
				Message message = (Message) messages[i];
				String msg = message.getFrom() + ": " + message.getContent().toString();
				System.out.print(msg);
				// mimeMessage.getSentDate();
				// mimeMessage.writeTo(System.out);
			}
		}
		System.out.println("------------------------------------------");
	}

	/**
	 * Remove notification for this session
	 * 
	 * @param sessionId
	 */
	public void removeWatcher(String sessionId, AsynchCallback callback) {
		log.debug("Remove watcher for " + sessionId);
		String resourceURI = this.sessionId2ResourceURI(sessionId);
		URL blobServerUrl = this.prplAppClient.getBlobManager().getResourceBlobServerDevice(resourceURI)
				.getServerURL();
		PRPLBlobServerAppClient blobAppClient = new PRPLBlobServerAppClient(blobServerUrl, this.prplAppClient
				.getOwnIdentity().getKey(), "");
		try {
			blobAppClient.removeResourceBlobWatcher(resourceURI, BlobManager.BLOB_WATCH_WRITE, this.callbackURL
					.toURI().toASCIIString());
		} catch (URISyntaxException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		Set<AsynchCallback> set = this.callbackMap.get(sessionId);
		if (set != null) {
			set.remove(callback);
		}
	}

	public static String MSG_RESOURCE = "Resource";
	public static String MSG_TEXT = "Text";

	/**
	 * Send resource message
	 * 
	 * @param sessionId
	 * @param resourceURI
	 */
	public void shareResource(String sessionId, String resourceURI) {
		String msgDescription = MSG_RESOURCE + " - " + sessionId;
		this.sendMessage(sessionId, "", resourceURI, msgDescription);

		String sessionResourceURI = this.sessionId2ResourceURI(sessionId);
		Object[] recp = prplAppClient.getResourceManager().getResourceMetaData(sessionResourceURI,
				PROPERTY_RECIPIENT_URI);

		if (recp != null) {
			for (int i = 0; i < recp.length; i++) {

				if (URIUtils.isGroupURI(recp[i].toString()) || URIUtils.isIdentityURI(recp[i].toString()))
					this.prplAppClient.getResourceManager().shareResourceWithIdentities(resourceURI,
							recp[i].toString());
			}
		}
		log.debug("Msg (resource type) sent");
	}

	/**
	 * Send text message
	 * 
	 * @param sessionId
	 * @param subject
	 * @param msg
	 */
	public void sendMessage(String sessionId, String subject, String msg) {
		String msgDescription = MSG_TEXT + " - " + sessionId;
		this.sendMessage(sessionId, subject, msg, msgDescription);
		log.debug("Msg (text type) sent");
	}

	/**
	 * Internal method to send a message
	 * 
	 * @param sessionId
	 * @param subject
	 * @param msg
	 * @param msgDesc
	 */
	private void sendMessage(String sessionId, String subject, String msg, String msgDesc) {

		String resourceURI = this.sessionId2ResourceURI(sessionId);
		BlobResource blobResource = prplAppClient.getResourceManager().getBlobResource(resourceURI);

		try {
			// Session session = Session.getDefaultInstance(System.getProperties());
			// Message message = new MimeMessage(session);
			Message message = new Message();

			Calendar cal = Calendar.getInstance();
			SimpleDateFormat df = new SimpleDateFormat(Message.DATE_FORMAT);
			String dateString = df.format(cal.getTime());

			message.setFrom(prplAppClient.getOwnIdentity().getKey());
			// message.setFrom(new InternetAddress(prplAppClient.getOwnIdentity().getKey()));
			// message.setRecipient(Message.RecipientType.TO, new InternetAddress(identityKey));

			if (subject != null)
				message.setSubject(dateString);
			else
				message.setSubject(sessionId + " - " + dateString);

			message.setText(msg);
			message.setDescription(msgDesc);
			message.setSentDate(cal.getTime());

			ByteArrayOutputStream bout = new ByteArrayOutputStream();
			String mboxHeader = "From " + prplAppClient.getOwnIdentity().getKey() + " " + dateString + "\n";
			bout.write(mboxHeader.getBytes());
			bout.write(message.toString().getBytes());
			// message.writeTo(bout);
			// bout.write(10); // \n
			// bout.write(new String("\n\n").getBytes());

			// Append msg to blob
			boolean isWritten = prplAppClient.getBlobManager().setResourceBlob(blobResource.getURI(), -1,
					bout.toByteArray());

			// message.writeTo(System.out);
			prplAppClient.getResourceManager().setResourceMetaLastModifiedDate(blobResource.getURI(),
					cal.getTimeInMillis());
			prplAppClient.getBlobManager().setResourceBlobLastModifiedDate(blobResource.getURI(),
					cal.getTimeInMillis());

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * Set notification for this session
	 * 
	 * @param sessionId
	 */
	public void setWatcher(String sessionId, AsynchCallback callback) {

		log.debug("Setting watcher for " + sessionId + "\tCallbackHash: " + callback.hashCode());

		if (this.watcherWorker == null || !this.watcherWorker.isAlive()) {
			this.startWatcherThread();
		}

		String resourceURI = this.sessionId2ResourceURI(sessionId);
		URL blobServerUrl = this.prplAppClient.getBlobManager().getResourceBlobServerDevice(resourceURI)
				.getServerURL();
		PRPLBlobServerAppClient blobAppClient = new PRPLBlobServerAppClient(blobServerUrl, this.prplAppClient
				.getOwnIdentity().getKey(), "");
		try {
			blobAppClient.setResourceBlobWatcher(resourceURI, BlobManager.BLOB_WATCH_WRITE, this.callbackURL
					.toURI().toASCIIString());

			// Default callback
			if (callback == null) {
				callback = new AsynchCallback() {
					@Override
					public void callback(String sessionId) {
						getMessages(sessionId, true);
						printMessages(sessionId);
					}
				};
			}

			Set<AsynchCallback> set = this.callbackMap.get(sessionId);
			if (set == null)
				set = new HashSet<AsynchCallback>();
			set.add(callback);
			this.callbackMap.put(sessionId, set);

		} catch (URISyntaxException e) {
			e.printStackTrace();
		}

	}

	/**
	 * Synch index with identity
	 * 
	 * @param identityURI
	 */
	public void synchWith(String identityURI) {

		if (identityURI == null)
			return;

		this.prplAppClient.clearIndexOf(identityURI);
		this.prplAppClient.syncIndexWith(identityURI);

		log.debug("Synced with " + identityURI);
	}

	/**
	 * Sync with all your friends
	 */
	public void synchWithAll() {
		Identity[] identities = prplAppClient.getIdentityManager().getAllIdentities();
		for (final Identity identity : identities) {
			if (!identity.getURI().equals(prplAppClient.getOwnIdentity().getURI())) {
				this.prplAppClient.clearIndexOf(identity.getURI());
				this.prplAppClient.syncIndexWith(identity.getURI());
			}
		}
		log.debug("Synced with everyone~~");
	}

	private void startWatcherThread() {

		this.watcherWorker = new Thread(new Runnable() {

			public void run() {
				while (true)
					try {
						List<String> resourceURIs = notification.getResourceURIs();
						for (String resourceURI : resourceURIs) {
							String sessionId = resourceURI2sessionId(resourceURI);
							Set<AsynchCallback> set = callbackMap.get(sessionId);
							if (set != null) {
								for (AsynchCallback callback : set) {
									if (callback != null)
										log.debug("Exec callback for sessionId " + sessionId + " with "
												+ callback.toString());
									callback.callback(sessionId);
								}
							}
						}
					} catch (Throwable e) {
						log.error("Error occured while processing notifications");
						e.printStackTrace();
					}
			}
		});

		this.watcherWorker.start();
	}

	private void startWebServer() {
		Thread PCMServer = new Thread(new Runnable() {
			public void run() {
				final Acme.Serve.Serve srv = new Acme.Serve.Serve();
				java.util.Properties properties = new java.util.Properties();
				properties.put("port", callbackURL.getPort());
				properties.setProperty(Acme.Serve.Serve.ARG_NOHUP, "nohup");
				srv.arguments = properties;

				NotificationHandlerServlet nServlet = new NotificationHandlerServlet(notification);
				srv.addServlet(callbackURL.getPath(), nServlet);
				log.info("Callback URL is " + callbackURL.toString());

				Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
					public void run() {
						try {
							srv.notifyStop();
						} catch (IOException ioe) {

						}
						srv.destroyAllServlets();
						System.out.println("Removing servlets!");
					}
				}));
				srv.serve();
			}
		});
		PCMServer.start();
	}

	/**
	 * Get list of buddies with their profile photo and contact information
	 * 
	 * @return
	 */
	public BuddyInfo[] getBuddyList() {

		List<BuddyInfo> buddyList = new ArrayList<BuddyInfo>();

		// Get list of contacts and their profile photos
		Map<String, BuddyInfo> buddyMap = new HashMap<String, BuddyInfo>();
		String query = "SELECT ?fullName ?photoResource ?fbStatus where {	" + "	?contact rdf:type prpl:Person.	"
				+ "	?contact prpl:fbstatus ?fbStatus. " + "	?contact prpl:fullName ?fullName. "
				+ "	?contact prpl:photo ?photoResource.	" + " }";

		log.debug(query);
		QueryResultIterator qr = prplAppClient.getResourceManager().runQuery(query);

		while (qr.hasNext()) {

			QueryResultIterator.Solution solution = qr.next();
			Iterator<String> varIter = solution.varNames();

			BuddyInfo buddy = new BuddyInfo();
			buddy.name = solution.getString("fullName");
			buddy.photoResource = solution.getBlobResource("photoResource");
			buddyMap.put(buddy.name, buddy);
		}

		// Get list of identities and match with their profile photo and other meta
		Identity identities[] = prplAppClient.getIdentityManager().getAllIdentities();

		for (Identity identity : identities) {

			// Skip self
			if (identity.equals(prplAppClient.getOwnIdentity()))
				continue;

			BuddyInfo buddy = buddyMap.get(identity.getName());
			if (buddy == null) {
				buddy = new BuddyInfo();
				buddy.name = (identity.getName() != null) ? identity.getName() : identity.getKey();
			}

			buddy.identity = identity;

			BlobResource[] msgResources = this.getAllCommunicationResourcesWith(identity.getURI());
			if (msgResources != null) {
				buddy.msgResources = msgResources;
				buddy.numOfMsg = msgResources.length;
			} else
				buddy.numOfMsg = 0;

			buddyList.add(buddy);
		}

		return buddyList.toArray(new BuddyInfo[] {});
	}

	public class BuddyInfo {
		public Identity identity;
		public BlobResource photoResource;
		public BlobResource[] msgResources;
		public String name;
		public int numOfMsg;

		@Override
		public String toString() {
			return identity.getKey();
		}
	}

	public static interface AsynchCallback {
		public void callback(String sessionId);
	}

	public static void main(String args[]) {

		if (args.length > 0) {
			try {
				PRPLProperties.loadProperties(args[0]);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		String LIST = "l", SEND = "s", RECV = "r", JOIN = "j", CREATE = "c", END = "e", QUIT = "q", WATCH = "w", INVITE = "i", SYNC = "sync";

		PRPLTalk prplTalk = new PRPLTalk();
		prplTalk.synchWithAll();

		String sessionId = new String();
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		String userInput = new String();
		System.out.println("Welcome to PRPLTalk, " + PRPLProperties.getProperty("prpl.user.name"));

		while (!userInput.equals(QUIT)) {
			try {
				System.out.print(sessionId + ">>");
				userInput = in.readLine();
				String[] tokens = userInput.split(" ");

				if (tokens[0].equalsIgnoreCase(LIST)) {

					BlobResource[] blobResources;
					if (tokens.length > 1) {
						String identityKey = tokens[1];
						String identityURI = URIUtils.getIdentityURI(identityKey);
						blobResources = prplTalk.getAllCommunicationResourcesWith(identityURI);
					} else
						blobResources = prplTalk.getAllCommunicationResources();

					System.out.println("------------------------------------------");
					for (int i = 0; i < blobResources.length; i++) {
						BlobResource communication = blobResources[i];
						Object[] metadata = communication.getMetaData(PROPERTY_SESSION_ID_URI);
						String sid = (metadata.length > 0) ? metadata[0].toString() : "";
						metadata = communication.getMetaData(PROPERTY_RECIPIENT_URI);
						Object[] recipients = metadata;
						String metaDate = communication.getLastModifiedDate().getTime().toString();
						// String blobDate = communication.getBlobLastModifiedDate().getTime().toString();
						System.out
								.println(i + "\tCreatedBy: " + communication.getOwner().getURI() + "\tRecp:"
										+ Arrays.toString(recipients) + "\tSessionId: " + sid + "\tLastMDate: "
										+ metaDate);
					}
					System.out.println("------------------------------------------");
				}
				if (tokens[0].equalsIgnoreCase(CREATE)) {
					String identities[] = Arrays.copyOfRange(tokens, 1, tokens.length);
					for (int i = 0; i < identities.length; i++) {
						identities[i] = URIUtils.getIdentityURI(identities[i]);
					}
					sessionId = prplTalk.startSession(identities);
					System.out.println("Created session (" + sessionId + ") with " + Arrays.toString(identities));
				}
				if (tokens[0].equalsIgnoreCase(JOIN)) {

					if (tokens.length > 1 && prplTalk.joinSession(tokens[1])) {
						sessionId = tokens[1];
						System.out.println("Joined session (" + sessionId + ")");
					} else {
						System.out.println("Failed to join session (" + sessionId + ")");
					}
				}
				if (tokens[0].equalsIgnoreCase(SEND)) {
					if (sessionId != null) {
						prplTalk.sendMessage(sessionId, null, userInput
								.substring(userInput.indexOf(SEND + " ") + 2));
						System.out.println("Sent a messegae.");
					} else
						System.out.println("You are currently not in any session");
					// prplTalk.printMessages(sessionId);
				}
				if (tokens[0].equalsIgnoreCase(INVITE)) {
					if (sessionId != null) {

						String identities[] = Arrays.copyOfRange(tokens, 1, tokens.length);
						for (int i = 0; i < identities.length; i++) {
							identities[i] = URIUtils.getIdentityURI(identities[i]);
						}
						prplTalk.invite(sessionId, identities);
						System.out.println("Invited " + Arrays.toString(identities));
					} else
						System.out.println("You are currently not in any session");
				}
				if (tokens[0].equalsIgnoreCase(RECV)) {
					if (sessionId != null) {
						prplTalk.getMessages(sessionId, true);
						prplTalk.printMessages(sessionId);
					} else
						System.out.println("You are currently not in any session");
				}
				if (tokens[0].equalsIgnoreCase(WATCH)) {
					sessionId = tokens[1];
					prplTalk.setWatcher(sessionId, null);
				}
				if (tokens[0].equalsIgnoreCase(END)) {
					if (sessionId != null) {
						prplTalk.endSession(sessionId);
						sessionId = "";
						System.out.println("Ended session " + sessionId);
					} else
						System.out.println("You are currently not in any session");
				}
				if (tokens[0].equalsIgnoreCase(SYNC)) {
					String identityKey = tokens[1];
					if (identityKey != null && identityKey.equals("all")) {
						prplTalk.synchWithAll();
					}
					prplTalk.synchWith(URIUtils.getIdentityURI(identityKey));
					System.out.println("Synched with " + identityKey);
				}

			} catch (Exception e) {
				System.err.println(e);
			}

		}
		System.out.println("Bye!");
		System.exit(0);
	}
}
